﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;

namespace DARE
{
    /// <summary>
    /// This class manages the Keyboard events.
    /// </summary>
    /// <example>
    /// <code>
    /// foreach (DARE.CKeyboardEvent key in m_Dare.InputMgr.Keyboard.KeyPressedEvent)
    /// {
    ///     switch (key.Key)
    ///     {
    ///         // exit
    ///         case Keys.Escape: this.Exit(); break;
    ///     }
    /// }
    /// </code>
    /// </example>
    public class CKeyboard : CInputProvider<KeyboardState>
    {
        #region fields

        private Dictionary<Keys, List<CGameObject>> m_registeredGameObjects;
        private List<Keys> m_keyPressedEvent;
        private List<Keys> m_keyReleasedEvent;

        private List<Keys> m_pressedLastFrame;
        private List<Keys> m_pressed;

        #endregion

        #region properties

        public List<Keys> KeyPressedEvent { get { return m_keyPressedEvent; } }
        public List<Keys> KeyReleasedEvent { get { return m_keyReleasedEvent; } }
        public KeyboardState KeyboardState { get; private set; }

        #endregion

        #region ctor

        public CKeyboard()
        {
            m_keyReleasedEvent = new List<Keys>();
            m_keyPressedEvent = new List<Keys>();
            m_registeredGameObjects = new Dictionary<Keys, List<CGameObject>>();
            m_pressedLastFrame = new List<Keys>();
            m_pressed = new List<Keys>();
            base.RegisterProvider(new CXnaKeyboardProvider() { Enabled = true });
        }

        #endregion

        #region methods

        public void RemoveListener(CGameObject gameObject)
        {
            foreach (List<CGameObject> list in m_registeredGameObjects.Values)
            {
                if (list.Contains(gameObject))
                    list.Remove(gameObject);
            }
        }

        public CGameObject RegisterGameObjectOnKey(CGameObject go, CKeyboardEvent key)
        {
            if (!m_registeredGameObjects.ContainsKey(key.Key))
                m_registeredGameObjects[key.Key] = new List<CGameObject>();
            m_registeredGameObjects[key.Key].Add(go);
            return go;
        }

        public CGameObject UnRegisterGameObjectOnKey(CGameObject go, CKeyboardEvent key)
        {
            if (m_registeredGameObjects.ContainsKey(key.Key))
                m_registeredGameObjects[key.Key].Remove(go);
            return go;
        }

        public CGameObject UnRegisterGameObjectOnAllKeys(CGameObject go)
        {
            foreach (List<CGameObject> list in m_registeredGameObjects.Values)
                if (list.Contains(go))
                    list.Remove(go);
            return go;
        }

        public void UnRegisterAllGameObjects()
        {
            foreach (List<CGameObject> list in m_registeredGameObjects.Values)
                list.Clear();
            m_registeredGameObjects.Clear();
        }

        public void Clear()
        {
            m_keyPressedEvent.Clear();
            m_keyReleasedEvent.Clear();
        }

        private bool EventContains(Keys key, List<Keys> keysEvents)
        {
            foreach (Keys keyboardEvent in keysEvents)
                if (keyboardEvent == key)
                    return true;
            return false;
        }

        public void Update()
        {
            if (!base.ProviderEnable)
                return;
            KeyboardState = base.GetState();
            foreach (Keys key in m_pressedLastFrame)
                if (!m_keyReleasedEvent.Contains(key) && KeyboardState.IsKeyUp(key))
                {
                    CKeyboardEvent k = new CKeyboardEvent(key);
                    m_keyReleasedEvent.Add(k.Key);
                    if (m_registeredGameObjects.ContainsKey(k.Key))
                        foreach (CGameObject go in m_registeredGameObjects[k.Key])
                            if (!go.IsSelfish || (go.Node != null && CDare.Instance.InputMgr.Mouse.MouseIntersectInfo.ContainsKey(go.Node.Render3D) && CDare.Instance.InputMgr.Mouse.MouseIntersectInfo[go.Node.Render3D].ContainsKey(go.Node)))
                                go.OnKeyReleasedMethod(k);
                    m_pressed.Remove(key);
                }
            m_pressedLastFrame.Clear();
            Keys[] keys = KeyboardState.GetPressedKeys();
            foreach (Keys key in keys)
            {
                m_pressedLastFrame.Add(key);
                if (!m_keyPressedEvent.Contains(key) && !m_pressed.Contains(key))
                {
                    CKeyboardEvent k = new CKeyboardEvent(key);
                    m_keyPressedEvent.Add(k.Key);
                    if (m_registeredGameObjects.ContainsKey(k.Key))
                        foreach (CGameObject go in m_registeredGameObjects[k.Key])
                            if (!go.IsSelfish || (go.Node != null && CDare.Instance.InputMgr.Mouse.MouseIntersectInfo.ContainsKey(go.Node.Render3D) && CDare.Instance.InputMgr.Mouse.MouseIntersectInfo[go.Node.Render3D].ContainsKey(go.Node))) 
                                go.OnKeyPressedMethod(k);
                    m_pressed.Add(key);
                }
            }
        }

        #endregion

    }
}
